using System;
using System.IO;
using System.Collections;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowFinder
{

	public class MainForm : System.Windows.Forms.Form
	{

		//HotKeyFilter object
        private HotKeyFilter HotKeys;
        private System.Windows.Forms.Button ShowButton;
        private TextBox FindBox;
        private System.ComponentModel.IContainer components;
        private NotifyIcon NotifyIcon;
        private ContextMenuStrip NotifyMenu;
        private ToolStripMenuItem ExitMenuItem;
        private ToolStripMenuItem ShowMenuItem;
        private ToolStripSeparator toolStripSeparator1;
        private TextBox TitleBox;
        private TextBox ModuleNameBox;
        private ColumnHeader Title;
        private ColumnHeader Process;
        private Panel panel2;
        private TableLayoutPanel tableLayoutPanel1;
        private Panel panel1;
        private ListView WindowListView;
        private Button HideButton;
        private ToolStripMenuItem settingsToolStripMenuItem;

        private readonly WindowList m_windowList = new WindowList();

        

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
            this.components = new System.ComponentModel.Container();
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
            System.Windows.Forms.ListViewGroup listViewGroup1 = new System.Windows.Forms.ListViewGroup("Recent", System.Windows.Forms.HorizontalAlignment.Left);
            System.Windows.Forms.ListViewGroup listViewGroup2 = new System.Windows.Forms.ListViewGroup("All", System.Windows.Forms.HorizontalAlignment.Left);
            this.ShowButton = new System.Windows.Forms.Button();
            this.FindBox = new System.Windows.Forms.TextBox();
            this.NotifyIcon = new System.Windows.Forms.NotifyIcon(this.components);
            this.NotifyMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
            this.settingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
            this.ShowMenuItem = new System.Windows.Forms.ToolStripMenuItem();
            this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
            this.ExitMenuItem = new System.Windows.Forms.ToolStripMenuItem();
            this.TitleBox = new System.Windows.Forms.TextBox();
            this.ModuleNameBox = new System.Windows.Forms.TextBox();
            this.WindowListView = new System.Windows.Forms.ListView();
            this.Title = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
            this.Process = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
            this.panel2 = new System.Windows.Forms.Panel();
            this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
            this.panel1 = new System.Windows.Forms.Panel();
            this.HideButton = new System.Windows.Forms.Button();
            this.NotifyMenu.SuspendLayout();
            this.panel2.SuspendLayout();
            this.tableLayoutPanel1.SuspendLayout();
            this.panel1.SuspendLayout();
            this.SuspendLayout();
            // 
            // ShowButton
            // 
            this.ShowButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.ShowButton.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.ShowButton.Location = new System.Drawing.Point(15, 17);
            this.ShowButton.Name = "ShowButton";
            this.ShowButton.Size = new System.Drawing.Size(85, 23);
            this.ShowButton.TabIndex = 0;
            this.ShowButton.Text = "Show";
            this.ShowButton.Click += new System.EventHandler(this.ShowButton_Click);
            // 
            // FindBox
            // 
            this.tableLayoutPanel1.SetColumnSpan(this.FindBox, 2);
            this.FindBox.Dock = System.Windows.Forms.DockStyle.Top;
            this.FindBox.Location = new System.Drawing.Point(3, 3);
            this.FindBox.Name = "FindBox";
            this.FindBox.Size = new System.Drawing.Size(638, 20);
            this.FindBox.TabIndex = 0;
            this.FindBox.TextChanged += new System.EventHandler(this.FindBox_TextChanged);
            this.FindBox.KeyUp += new System.Windows.Forms.KeyEventHandler(this.FindBox_KeyUp);
            // 
            // NotifyIcon
            // 
            this.NotifyIcon.ContextMenuStrip = this.NotifyMenu;
            this.NotifyIcon.Icon = ((System.Drawing.Icon)(resources.GetObject("NotifyIcon.Icon")));
            this.NotifyIcon.Text = "WindowFinder";
            this.NotifyIcon.Visible = true;
            this.NotifyIcon.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.NotifyIcon_MouseDoubleClick);
            // 
            // NotifyMenu
            // 
            this.NotifyMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.settingsToolStripMenuItem,
            this.ShowMenuItem,
            this.toolStripSeparator1,
            this.ExitMenuItem});
            this.NotifyMenu.Name = "NotifyMenu";
            this.NotifyMenu.RenderMode = System.Windows.Forms.ToolStripRenderMode.System;
            this.NotifyMenu.Size = new System.Drawing.Size(153, 98);
            this.NotifyMenu.ItemClicked += new System.Windows.Forms.ToolStripItemClickedEventHandler(this.NotifyMenu_ItemClicked);
            // 
            // settingsToolStripMenuItem
            // 
            this.settingsToolStripMenuItem.Name = "settingsToolStripMenuItem";
            this.settingsToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
            this.settingsToolStripMenuItem.Text = "Settings...";
            this.settingsToolStripMenuItem.Click += new System.EventHandler(this.SettingsButton_Click);
            // 
            // ShowMenuItem
            // 
            this.ShowMenuItem.Name = "ShowMenuItem";
            this.ShowMenuItem.Size = new System.Drawing.Size(152, 22);
            this.ShowMenuItem.Text = "Show";
            // 
            // toolStripSeparator1
            // 
            this.toolStripSeparator1.Name = "toolStripSeparator1";
            this.toolStripSeparator1.Size = new System.Drawing.Size(149, 6);
            // 
            // ExitMenuItem
            // 
            this.ExitMenuItem.Name = "ExitMenuItem";
            this.ExitMenuItem.Size = new System.Drawing.Size(152, 22);
            this.ExitMenuItem.Text = "Exit";
            // 
            // TitleBox
            // 
            this.TitleBox.Dock = System.Windows.Forms.DockStyle.Top;
            this.TitleBox.Location = new System.Drawing.Point(5, 5);
            this.TitleBox.Name = "TitleBox";
            this.TitleBox.ReadOnly = true;
            this.TitleBox.Size = new System.Drawing.Size(508, 20);
            this.TitleBox.TabIndex = 0;
            // 
            // ModuleNameBox
            // 
            this.ModuleNameBox.Dock = System.Windows.Forms.DockStyle.Bottom;
            this.ModuleNameBox.Location = new System.Drawing.Point(5, 31);
            this.ModuleNameBox.Name = "ModuleNameBox";
            this.ModuleNameBox.ReadOnly = true;
            this.ModuleNameBox.Size = new System.Drawing.Size(508, 20);
            this.ModuleNameBox.TabIndex = 1;
            // 
            // WindowListView
            // 
            this.WindowListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
            this.Title,
            this.Process});
            this.tableLayoutPanel1.SetColumnSpan(this.WindowListView, 2);
            this.WindowListView.Dock = System.Windows.Forms.DockStyle.Fill;
            this.WindowListView.FullRowSelect = true;
            listViewGroup1.Header = "Recent";
            listViewGroup1.Name = "Recent";
            listViewGroup2.Header = "All";
            listViewGroup2.Name = "All";
            this.WindowListView.Groups.AddRange(new System.Windows.Forms.ListViewGroup[] {
            listViewGroup1,
            listViewGroup2});
            this.WindowListView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
            this.WindowListView.HideSelection = false;
            this.WindowListView.Location = new System.Drawing.Point(3, 30);
            this.WindowListView.MultiSelect = false;
            this.WindowListView.Name = "WindowListView";
            this.WindowListView.Size = new System.Drawing.Size(638, 221);
            this.WindowListView.TabIndex = 1;
            this.WindowListView.UseCompatibleStateImageBehavior = false;
            this.WindowListView.View = System.Windows.Forms.View.Details;
            this.WindowListView.SelectedIndexChanged += new System.EventHandler(this.WindowListView_SelectedIndexChanged);
            this.WindowListView.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.WindowListView_MouseDoubleClick);
            // 
            // Title
            // 
            this.Title.Text = "Title";
            this.Title.Width = 519;
            // 
            // Process
            // 
            this.Process.Text = "Process";
            this.Process.Width = 98;
            // 
            // panel2
            // 
            this.panel2.Controls.Add(this.TitleBox);
            this.panel2.Controls.Add(this.ModuleNameBox);
            this.panel2.Dock = System.Windows.Forms.DockStyle.Fill;
            this.panel2.Location = new System.Drawing.Point(3, 257);
            this.panel2.Name = "panel2";
            this.panel2.Padding = new System.Windows.Forms.Padding(5);
            this.panel2.Size = new System.Drawing.Size(518, 56);
            this.panel2.TabIndex = 3;
            // 
            // tableLayoutPanel1
            // 
            this.tableLayoutPanel1.ColumnCount = 2;
            this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
            this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 120F));
            this.tableLayoutPanel1.Controls.Add(this.FindBox, 0, 0);
            this.tableLayoutPanel1.Controls.Add(this.WindowListView, 0, 1);
            this.tableLayoutPanel1.Controls.Add(this.panel2, 0, 2);
            this.tableLayoutPanel1.Controls.Add(this.panel1, 1, 2);
            this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
            this.tableLayoutPanel1.Name = "tableLayoutPanel1";
            this.tableLayoutPanel1.RowCount = 3;
            this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 27F));
            this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
            this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 62F));
            this.tableLayoutPanel1.Size = new System.Drawing.Size(644, 316);
            this.tableLayoutPanel1.TabIndex = 0;
            // 
            // panel1
            // 
            this.panel1.Controls.Add(this.HideButton);
            this.panel1.Controls.Add(this.ShowButton);
            this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.panel1.Location = new System.Drawing.Point(527, 257);
            this.panel1.Name = "panel1";
            this.panel1.Size = new System.Drawing.Size(114, 56);
            this.panel1.TabIndex = 2;
            // 
            // HideButton
            // 
            this.HideButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
            this.HideButton.Location = new System.Drawing.Point(-20, -20);
            this.HideButton.Name = "HideButton";
            this.HideButton.Size = new System.Drawing.Size(15, 15);
            this.HideButton.TabIndex = 2;
            this.HideButton.Text = "h";
            this.HideButton.UseVisualStyleBackColor = true;
            this.HideButton.Click += new System.EventHandler(this.HideButton_Click);
            // 
            // MainForm
            // 
            this.AcceptButton = this.ShowButton;
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.CancelButton = this.HideButton;
            this.ClientSize = global::WindowFinder.Properties.Settings.Default.Size;
            this.Controls.Add(this.tableLayoutPanel1);
            this.DataBindings.Add(new System.Windows.Forms.Binding("ClientSize", global::WindowFinder.Properties.Settings.Default, "Size", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
            this.DataBindings.Add(new System.Windows.Forms.Binding("Opacity", global::WindowFinder.Properties.Settings.Default, "Opacity", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow;
            this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
            this.Name = "MainForm";
            this.Opacity = global::WindowFinder.Properties.Settings.Default.Opacity;
            this.ShowInTaskbar = false;
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
            this.Text = "Window Finder";
            this.TopMost = true;
            this.Deactivate += new System.EventHandler(this.MainForm_Deactivate);
            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing);
            this.Load += new System.EventHandler(this.MainForm_Load);
            this.VisibleChanged += new System.EventHandler(this.MainForm_VisibleChanged);
            this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.MainForm_KeyUp);
            this.NotifyMenu.ResumeLayout(false);
            this.panel2.ResumeLayout(false);
            this.panel2.PerformLayout();
            this.tableLayoutPanel1.ResumeLayout(false);
            this.tableLayoutPanel1.PerformLayout();
            this.panel1.ResumeLayout(false);
            this.ResumeLayout(false);

		}
		#endregion

		public MainForm()
		{
			InitializeComponent();
		}

		[STAThread]
		static void Main(string[] args) 
		{
            Application.EnableVisualStyles();
            MainForm form = new MainForm();

            if (args.Length > 0 && args[0] == "-t")
            {
                // put in tray right away
                form.Visible = false;
            }

			Application.Run(form);
		}

		private void MainForm_Load(object sender, System.EventArgs e)
		{
            //PickWindows();

            HotKeys = new HotKeyFilter();
            HotKeys.Parent = this;

			//Add a WM_HOTKEY message filter
			Application.AddMessageFilter(HotKeys);

            // Load Hotkeys
            LoadHotkeys();

			//subscribe to hotkey events from the message filter
			HotKeys.HotKeyEvent += new HotKeyFilter.HotKeyHandler(OnHotKey);
		}

		/// <summary>
		/// Shows Window Picker dialog and adds all selected windows to the listbox
		/// </summary>
		private void PickWindows()
		{
			this.TopMost = false;

			//show the Window Picker Dialog
            Chooser dlg = new Chooser();
			//if they choose accept...
			if (dlg.ShowDialog() == DialogResult.OK)
			{
                //wndList = new ArrayList(dlg.SelectedWindows);
                //FilterWindows();
			}

			this.TopMost = true;
		}


        private void FilterWindows()
        {
            m_windowList.TitleFilter = this.FindBox.Text;

            WindowListView.BeginUpdate();
            WindowListView.Items.Clear();

            ImageList icons = new ImageList();
            
            ListViewGroup histGroup = WindowListView.Groups[0];
            foreach (Window wnd in m_windowList.History)
            {
                ListViewItem item = new ListViewItem(new string[] {wnd.Title, wnd.ProcessName});
                item.Tag = wnd;
                item.ImageIndex = icons.Images.Count;
                icons.Images.Add(wnd.ProcessIcon);

                histGroup.Items.Add(item);
                WindowListView.Items.Add(item);
            }
            ListViewGroup curGroup = WindowListView.Groups[1];
            foreach (Window wnd in m_windowList.Windows)
            {
                ListViewItem item = new ListViewItem(new string[] { wnd.Title, wnd.ProcessName });
                item.Tag = wnd;
                item.ImageIndex = icons.Images.Count;
                icons.Images.Add(wnd.ProcessIcon);

                curGroup.Items.Add(item);
                WindowListView.Items.Add(item);
            }
            WindowListView.SmallImageList = icons;
            WindowListView.EndUpdate();
            if (WindowListView.Items.Count > 0)
            {
                WindowListView.SelectedIndices.Clear();
                WindowListView.SelectedIndices.Add(0);
            }
        }

		/// <summary>
		/// HotKeyEvent handler
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="WParam">HotKey ID</param>
		private void OnHotKey(object sender, IntPtr WParam)
		{
			switch ((int)WParam)
			{
				case 666:
                    if (!this.Visible)
                    {
                        NotifyIcon_MouseDoubleClick(null, null);
                    }
                    else
                    {
                        Hide();
                    }
					break;
			}
		}

		private void SaveSettings()
		{
			Properties.Settings.Default.Save();
		}

        private void LoadHotkeys()
        {
            HotKeys.ReleaseKeys();
            HotKey hk = new HotKey(666, KeyCodes.deserializeModifier(Properties.Settings.Default.HideMods),
                                        KeyCodes.deserializeKey(Properties.Settings.Default.HideKey));
            HotKeys.Add(hk);
        }

		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		private void PickButton_Click(object sender, System.EventArgs e)
		{
			PickWindows();
		}

		private void SettingsButton_Click(object sender, System.EventArgs e)
		{
			this.TopMost = false;

			//show the settings dialog
			Settings dlg = new Settings();
			
			//update controls on settings dialog
			dlg.Opacity = this.Opacity;
            dlg.HideModifiers = KeyCodes.deserializeModifier(Properties.Settings.Default.HideMods);
            dlg.HideKey = KeyCodes.deserializeKey(Properties.Settings.Default.HideKey);

			//if they accept changes
			if (dlg.ShowDialog() == DialogResult.OK)
			{
				//deal with hotkey changes
                Properties.Settings.Default.HideKey = dlg.HideKey.serialize();
                Properties.Settings.Default.HideMods = dlg.HideModifiers.serialize();

                //update opacity
                Properties.Settings.Default.Opacity = dlg.Opacity;
                
                SaveSettings();
                LoadHotkeys();
				
				
			}

			this.TopMost = true;
		}

        private void FindBox_TextChanged(object sender, EventArgs e)
        {
            FilterWindows();
        }

        private void ShowButton_Click(object sender, EventArgs e)
        {
            Hide();

            foreach (ListViewItem i in WindowListView.SelectedItems)
            {
                Window wnd = (Window)i.Tag;
                m_windowList.show(wnd);
            }
        }

        private void FindBox_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Down)
            {
                WindowListView.Focus();
                int max = WindowListView.SelectedIndices.Count != 0 ? WindowListView.SelectedIndices[0] : 0;
                if (WindowListView.Items.Count > max && WindowListView.Items.Count < max + 1)
                {
                    WindowListView.SelectedIndices.Clear();
                    WindowListView.SelectedIndices.Add(max + 1);
                }
            }
        }

        private void MainForm_VisibleChanged(object sender, EventArgs e)
        {
            if (this.Visible)
            {
                m_windowList.Update();
                FilterWindows();
                Activate();
            }
            FindBox.Focus();
            FindBox.SelectAll();
        }

        private void VisListBox_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            ShowButton_Click(sender, null);
        }

        private void NotifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            Show();
        }

        private void NotifyMenu_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            if (e.ClickedItem == ExitMenuItem)
            {
                this.Close();
            }
            else if (e.ClickedItem == ShowMenuItem)
            {
                NotifyIcon_MouseDoubleClick(null, null);
            }
        }

        private void MainForm_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Escape)
            {
                Hide();
            }
        }

        private void MainForm_Deactivate(object sender, EventArgs e)
        {
            Hide();
        }

        private void WindowListView_SelectedIndexChanged(object sender, EventArgs e)
        {
            foreach (ListViewItem i in WindowListView.SelectedItems)
            {
                Window wnd = (Window) i.Tag;
                TitleBox.Text = wnd.Title;
                ModuleNameBox.Text = wnd.ProcessFile;
            }
        }

        private void WindowListView_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            ShowButton_Click(sender, null);
        }

        private void HideButton_Click(object sender, EventArgs e)
        {
            Hide();
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            SaveSettings();
        }

	}
}